package org.xs.web.util;

import java.beans.Introspector;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Reflections {
	
	
	public static Object invoke(Method method,Object target,Object... args) throws Exception{
		try {
			return method.invoke(target, args);
		} catch (IllegalArgumentException e) {
			String msg = "could not invoke method "+method +"with paramters "+args;
			throw new IllegalArgumentException(msg,e);
		} catch (Exception e) {
			 throw e;
		}  
	}
	
	public static Object invokeAndWrap(Method method,Object target,Object...args){
			try {
				return invoke(method, target, args);
			} catch (Exception e) {
				throw new RuntimeException("invoke method error:"+method,e);
			}
		 
	}
	
	public static Method getMethod(String name,Class<?> clazz){
		for(Method method : clazz.getMethods()){
			if(method.getName().equals(name)){
				return method;
			}
		}
		throw new IllegalStateException("no such method by name :"+name+"in class:"+clazz);
	}
	
	public static Method getMethodAndWrap(String name,Class<?> clazz){
		try {
			return getMethod(name, clazz);
		} catch (Exception e) {
			 
		}
		return null;
	}
	
	public static Method getGetterMethod(String name,Class<?> clazz){
		for(Method method : clazz.getMethods()){
			String methodName = method.getName();
			if(methodName.startsWith("get") && method.getParameterTypes().length == 0){
				if(Introspector.decapitalize(methodName.substring(3)).equals(name)){
					return method;
				}
			}
			if(methodName.startsWith("is") && method.getParameterTypes().length == 0){
				if(Introspector.decapitalize(methodName.substring(2)).equals(name)){
					return method;
				}
			}
		}
		throw new IllegalArgumentException("no such getter or is method class "+clazz+"."+name);
	}
	
	public static Method getSetterMethod(String name,Class<?> clazz){
		for(Method method : clazz.getMethods()){
			String methodName = method.getName();
			if(methodName.startsWith("set") && method.getParameterTypes().length == 1){
				if(Introspector.decapitalize(methodName.substring(3)).equals(name)){
					return method;
				}
			}
		}
		throw new IllegalArgumentException("no such setter method class "+clazz+"."+name);
	}
	
	public static void set(Field field,Object target,Object value) throws Exception{
		try {
			field.set(target, value);
		} catch (IllegalArgumentException e) {
			 String msg = "could not set field "+field+"with value "+value;
			 throw new IllegalArgumentException(msg,e);
		} catch (Exception e) {
			 throw e;
		}
	}
	public static void setAndWrap(Field field,Object target,Object value){
		try {
			set(field, target, value);
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	}
	
	public static Object get(Field field,Object target) throws Exception{
		try {
			return field.get(target);
		} catch (IllegalArgumentException e) {
			String msg = "could not get filed value"+field;
			throw new IllegalArgumentException(msg,e);
		} catch (Exception e) {
			throw e;
		}
	}
	public static Object getAnWrap(Field field,Object target){
		try {
			return field.get(target);
		} catch (Exception e) {
			 throw new IllegalArgumentException(e);
		}  
	}
	
	
	public static Field getField(String fieldName,Class<?> target){
		for(Class<?> clazz = target.getClass() ; clazz != null && clazz != Object.class ; clazz = clazz.getSuperclass()){
			for(Field field : clazz.getDeclaredFields()){
				if(field.getName().equals(fieldName)){
					return field;
				}
			}
		}
		return null;
	}
	
	public static Object get(String fieldName,Object target){
		if(target == null){
			throw new NullPointerException("Reflections target counld not be null");
		}
		Field field = getField(fieldName, target.getClass());
		if(field != null){
			return getAnWrap(field, target);
		}
		throw new IllegalArgumentException("could not found file from class :"+target.getClass());
	}
	
	public static Class<?> loadClassForName(String className) throws ClassNotFoundException{
		try {
			
			return Thread.currentThread().getContextClassLoader().loadClass(className);
			
		} catch (Exception e) {
			 return Class.forName(className);
		}
	}
}
